package com.lvcoding.auth2.auth.shizhan.grant;

import cn.hutool.extra.spring.SpringUtil;
import com.lvcoding.auth2.auth.shizhan.security.CustomUserDetailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.Assert;

import java.util.Map;
import java.util.Optional;

/**
 * 自定义认证提供者
 *
 * @author wuyanshen
 */
@Slf4j
public class CustomAuthenticationProvider implements AuthenticationProvider {


    private PasswordEncoder passwordEncoder;


    public CustomAuthenticationProvider() {
        setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());
    }

    protected void additionalAuthenticationChecks(CustomAuthenticationToken authentication) throws AuthenticationException {
        if (authentication.getCredentials() == null) {
            log.debug("Failed to authenticate since no credentials provided");
            throw new BadCredentialsException("Bad credentials");
        }
    }


    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        CustomAuthenticationToken requestToken = (CustomAuthenticationToken) authentication;

        // 认证类型
        String grantType = requestToken.getGrantType();

        // 此处已获得 客户端认证 获取对应 userDetailsService
        Authentication clientAuthentication = SecurityContextHolder.getContext().getAuthentication();
        String clientId = clientAuthentication.getName();

        Map<String, CustomUserDetailService> userDetailsServiceMap = SpringUtil.getBeansOfType(CustomUserDetailService.class);
        Optional<CustomUserDetailService> optional = userDetailsServiceMap.values().stream()
                .filter(service -> service.support(grantType))
                .findFirst();

        if (!optional.isPresent()) {
            throw new InternalAuthenticationServiceException("UserDetailsService error , not register");
        }

        // 认证类型
        String phone = (String) requestToken.getPrincipal();
        UserDetails userDetails = optional.get().loadUserByUsername(phone);

        CustomAuthenticationToken customAuthenticationToken = new CustomAuthenticationToken(userDetails);

        // 校验验证码是否正确
        additionalAuthenticationChecks(customAuthenticationToken);

        customAuthenticationToken.setDetails(authentication.getDetails());
        return customAuthenticationToken;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.isAssignableFrom(CustomAuthenticationToken.class);
    }


    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
        this.passwordEncoder = passwordEncoder;
    }

    protected PasswordEncoder getPasswordEncoder() {
        return this.passwordEncoder;
    }

}
